package com.atguigu.day03;

import java.util.concurrent.*;

/**
 * @ClassName MyThreadPoolDemo
 * @Description 此类描述:
 * @Author dangchen
 * @DateTime 2022-09-08 18:52
 * @Version 1.0
 */

/**
 * 线程池:
 * 主要特点:线程复用,控制最大并发数,管理线程
 * 优点:降低资源消耗(线程复用),提高响应速度(不用一直创建线程),提高线程得可管理性
 *
 * 线程池的底层原理
 *
 * 7个基本参数:核心线程数(银行周末值班人员),最大线程数(银行窗口),活跃时间,单位,阻塞队列(等候区座位),线程工厂(银行总部),拒绝策略
 *
 * 提交任务 -> 1.1任务数小于核心线程数,创建线程执行任务;
 *         -> 1.2任务数大于核心线程数,但是小于核心线程数与阻塞队列容量之和,则超出核心线程数的部分自动进入阻塞队列等候
 *         -> 1.3任务数大于核心线程数与阻塞队列容量之和,但是小于最大线程数与阻塞队列容量之和,则增加线程来支援核心线程,注意此时不是先处理阻塞队列里的线程,而是先处理新提交的任务
 *         ->1.4任务数大于最大线程数与阻塞队列容量之和,开启拒绝策略,不在接收任务提交
 * 2 当一个线程完成任务后,会自动在队列中领取其他任务
 * 3 当一个线程无事可做超过活跃时间,线程会判断
 *      -> 3.1 如果当前运行中的线程数大于核心线程数,那么就会停掉这个线程
 *      ->  3.2 所以线程池的所有任务执行结束后,它会收缩到核心线程数的大小
 *
 * Executors创建一池单个线程/多个线程/可变线程在工作中基本不用,因为最大线程数等于Integer的上限,会造成OOM(out of memory 内存溢出)
 *
 * 拒绝策略:JDK的内置拒绝策略均实现了RejectedExecutionHandler接口,任务数临界点就是最大线程数和阻塞队列容量之和
 * 1.AbortPolicy(默认):直接抛出RejectedExecutionException异常阻止系统正常运行
 * 2.CallerRunsPolicy:调用者运行,一种调节机制,该策略既不会抛弃任务,也不会抛出异常,而是将某些任务回退到调用者,从而降低新任务的流量
 * 3.discardPolicy:该策略默默地丢弃无法处理地任务,不予任何处理也不抛出异常.如果允许任务丢失,这是最好的一种策略.
 * 4.DiscardOldestPolicy:抛弃队列中等待最久的任务,然后把当前任务加入队列中,尝试再次提交当前任务.
 *
 */
public class MyThreadPoolDemo {
    public static void main(String[] args) {
        ExecutorService threadPool = new ThreadPoolExecutor(2,5,1L,TimeUnit.SECONDS,new LinkedBlockingQueue<>(3),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());

        try {
            for (int i = 1; i <= 8 ; i++) {
                int finalI = i;
                threadPool.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + "号\t工作人员在服务\t" + finalI +"号顾客");
                    try {
                        TimeUnit.MILLISECONDS.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });
            }
        }finally {
            threadPool.shutdown();
        }
    }

    private static void initPool() {
        //ExecutorService threadPool = Executors.newSingleThreadExecutor();//一池一线程
        //ExecutorService threadPool = Executors.newFixedThreadPool(5);//一池5线程
        ExecutorService threadPool = Executors.newCachedThreadPool();//线程数可变
        try {
            for (int i = 1; i <= 20 ; i++) {
                int finalI = i;
                threadPool.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + "\t工作人员在服务第" + finalI + "顾客");
                });

            }
        }finally {
            threadPool.shutdown();
        }
    }
}
